package pri.damai.xiaowu.auth.service;

import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import pri.damai.xiaowu.auth.enums.ResultEnum;
import pri.damai.xiaowu.common.core.exception.GlobalException;
import pri.damai.xiaowu.common.core.util.DateUtils;
import pri.damai.xiaowu.common.security.config.SecurityUtil;
import pri.damai.xiaowu.common.security.config.XiaoWuSecurityProperties;
import pri.damai.xiaowu.common.security.constant.AuthConstant;
import pri.damai.xiaowu.common.security.token.RuiRuanAccessToken;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 *
 * @Desc
 * @Author DaMai
 * @Date 2021/12/9 18:34
 * 但行好事，莫问前程。
 */
@Slf4j
@Component
public class TokenService {

    @Resource
    RedisTemplate<String, Object> redisTemplate;
    @Resource
    XiaoWuSecurityProperties securityProperties;
    @Value("${xiaowu.security.expiration-interval}")
    long expirationInterval;
    @Resource
    SecurityUtil securityUtil;

    public void checkToken(String token) {

        Claims claims;
        try {
            claims = securityUtil.getClaims(token);
        } catch (Exception e) {
            log.info("token 解析失败。token:{}", token);
            throw new GlobalException(ResultEnum.INVALID_TOKEN);
        }

        String userId = claims.get(AuthConstant.USER_ID_KEY, String.class);

        String tokenRedisKey = getTokenRedisKey(userId);

        RuiRuanAccessToken ruiRuanAccessToken = (RuiRuanAccessToken) redisTemplate.opsForValue()
                .get(tokenRedisKey);

        if (Objects.isNull(ruiRuanAccessToken) || !Objects.equals(ruiRuanAccessToken.getToken(), token)) {
            log.warn("Redis 中不存在此 Token。Token:{}", token);
            throw new GlobalException(ResultEnum.INVALID_TOKEN);
        }

        // 增加 token 保活校验
        boolean isMoreThan = isMoreThanTimeInterval(ruiRuanAccessToken, expirationInterval);

        if (isMoreThan) {
            redisTemplate.delete(tokenRedisKey);
            throw new GlobalException(ResultEnum.INVALID_TOKEN);
        }
    }

    /**
     * 检查时间间隔
     * @apiNote [附加描述]
     * @param ruiRuanAccessToken token 实体
     * @param expirationInterval 请求间隔
     * @return boolean
     * @author DaMai
     * @date 2021/12/7 15:14
     */
    protected boolean isMoreThanTimeInterval(RuiRuanAccessToken ruiRuanAccessToken, long expirationInterval) {
        // 最后一次调用时间
        Long lastCallTime = ruiRuanAccessToken.getLastCallTime();
        LocalDateTime lastCallDateTime;
        if (Objects.isNull(lastCallTime)) {
            lastCallDateTime = LocalDateTime.now();
        } else {
            lastCallDateTime = DateUtils.asLocalDateTime(lastCallTime);
        }

        // 限制时间
        LocalDateTime nowDateTime = LocalDateTime.now();
        LocalDateTime limitDateTime = lastCallDateTime.plusSeconds(expirationInterval);

        return nowDateTime.isAfter(limitDateTime);
    }

    /**
     * 获取存放Token的RedisKey
     * @apiNote [附加描述]
     * @param userId 用户Id
     * @return java.lang.String
     * @author DaMai
     * @date 2021/10/29 10:43
     */
    private String getTokenRedisKey(String userId) {
        return securityProperties.getTokenRedisKey() + userId;
    }

}
